package demo.db.tsdb.prometheus;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import demo.java.net.HttpDemo;
import demo.java.time.DateTimeDemo;
import demo.vo.exp.ServiceException;
import demo.vo.http.ResponseVo;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/promql/prometheus-promql-with-http-api
 * <p>
 * 响应数据类型
 * <p>
 * <li>区间向量：matrix
 * <pre>
 *     [
 *     {
 *     "metric": { "<label_name>": "<label_value>", ... },
 *     "values": [ [ <unix_time>, "<sample_value>" ], ... ]
 *     },
 *     ...
 *     ]
 * <pre/>
 * <li>瞬时向量：vector
 * <pre>
 * [
 *   {
 *     "metric": { "<label_name>": "<label_value>", ... },
 *     "value": [ <unix_time>, "<sample_value>" ]
 *   },
 *   ...
 * ]
 * <pre/>
 * <li>标量：scalar,响应格式： [ <unix_time>, "<scalar_value>" ]
 * <li>字符串：string，响应格式：[ <unix_time>, "<string_value>" ]
 */
public class PromQLTest {

    private static Logger logger = LoggerFactory.getLogger(PromQLTest.class);

    public static final String HOST = "http://192.168.41.80:9090";

    /**
     * Prometheus定义了4种不同的指标类型(metric type)：
     * <li>Counter（计数器）、只增不减的计数器。常见的监控指标，如http_requests_total，node_cpu都是Counter类型的监控指标。
     * 一般在定义Counter类型指标的名称时推荐使用_total作为后缀。
     * <li>Gauge（仪表盘）、可增可减的仪表盘。Gauge类型的指标侧重于反应系统的当前状态。因此这类指标的样本数据可增可减。
     * 常见指标如：node_memory_MemFree（主机当前空闲的内容大小）、node_memory_MemAvailable（可用内存大小）都是Gauge类型的监控指标。
     * <li>Histogram（直方图）、Histogram和Summary主用用于统计和分析样本的分布情况。
     * <li>Summary（摘要）。Histogram和Summary主用用于统计和分析样本的分布情况。
     */
    public void metric() {

    }

    @Test
    public void testQuery() {
        String promQL = "jvm_buffer_pool_used_bytes";
        Long time = null;
        try {
            JSONObject result = query(promQL, time);
            System.out.println(result.toJSONString(SerializerFeature.PrettyFormat));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }



    @Test
    public void testQueryRange() {
        String promQL = "jvm_buffer_pool_used_bytes";
        Long time = null;
        try {
            long end = System.currentTimeMillis();
            long start = end - TimeUnit.MINUTES.toMillis(30);
            JSONObject result = queryRange(promQL, start, end, "60s");
            System.out.println(result.toString(SerializerFeature.PrettyFormat));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**
     * 瞬时数据查询
     *
     * @param promQL PromQL表达式
     * @param time   用于指定用于计算PromQL的时间戳。可选参数，默认情况下使用当前系统时间。
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public static JSONObject query(String promQL, Long time)
            throws IOException, ServiceException {
        String query = "/api/v1/query?query=" + promQL;
        if (time != null) {
            query += "&time=" + DateTimeDemo.toLocalDateTime(time).toString();
        }
        String url = HOST + query;
        ResponseVo responseVo = HttpDemo.get(url, 3000, 9000);
        logger.info("{}", JSON.toJSONString(responseVo, true));
        if (responseVo.isHttpStatus2XX()) {
            return JSON.parseObject(responseVo.getContent());
        }
        throw new ServiceException(responseVo.toString());
    }

    /**
     * 区间数据查询。当使用QUERY_RANGE API查询PromQL表达式时，返回结果一定是一个区间向量。
     * <p>
     * 在QUERY_RANGE API中PromQL只能使用瞬时向量选择器类型的表达式。
     *
     * @param promQL PromQL表达式。
     * @param start  起始时间
     * @param end    结束时间
     * @param step   查询步长
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public static JSONObject queryRange(String promQL, long start, long end, String step)
            throws IOException, ServiceException {
        String queryPattern = "/api/v1/query_range?query=%s&start=%s&end=%s&step=%s";
        String startTime = DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochMilli(start));
        String endTime = DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochMilli(end));
        String url = HOST + String.format(queryPattern, promQL, startTime, endTime, step);
        ResponseVo responseVo = HttpDemo.get(url, 3000, 9000);
        logger.info("{}", JSON.toJSONString(responseVo, true));
        if (responseVo.isHttpStatus2XX()) {
            return JSON.parseObject(responseVo.getContent());
        }
        throw new ServiceException(responseVo.toString());
    }


}
